<?php
if( !defined('CORE') ) exit('Request Error!');
/**
 * 默认缓存类
 *
 * 使用缓存应该比较注意的问题，没特殊原因一般都使用memcache或memcached作为缓存类型，对于很小规模的应用， 可以考虑用 file 作为缓存， 
 * 缓存进行 set/get/deldte 时务必指定 prefix，实际上系统最终得到的 key 是 base64_encode( self::df_prefix.'_'.$prefix.'_'.$key )
 * 为什么要这样做呢？
 * 因为memcache或memcached对应用缓存服务器群通常是很多网站一起使用的，如果没前缀区分，很容易会错把目标网站的同名缓存给crear掉
 *
 * @since 2011-07-20
 * @author itprato<2500875@qq>
 * @version $Id$
 */
define('CLS_CACHE', true);
class cache
{
   //文件缓存系统或memcache游标
   private $mc_handle = null;
   
   //缓存类型（file|memcache|memcached）
   public static $cache_type = 'file';
   
   //key默认前缀
   private static $df_prefix = 'mc_df_';
   
   //默认缓存时间
   private static $cache_time = 7200;
   
   //当前类实例
   private static $instance = null;
   
   //是否使用内存数组
   public static $need_mem = true;
   
   //配置信息md5
   public static $cache_config_md5 = null;
   
   /**
    * 构造函数
    * @return void
    */
    public function __construct($config = array())
    {
        if( !config('CACHE_ENABLE') ) 
        {
            return;
        }

        self::$df_prefix  = isset($config['CACHE_PREFIX']) ? $config['CACHE_PREFIX'] : config('CACHE_PREFIX');
        self::$cache_time = isset($config['CACHE_TIME']) ? $config['CACHE_TIME'] : config('CACHE_TIME');
        self::$cache_type = isset($config['CACHE_TYPE']) ? $config['CACHE_TYPE'] : config('CACHE_TYPE');
        
        if( self::$cache_type == 'file' )
        {
            $cache_file_name = isset($config['CACHE_FILENAME']) ? $config['CACHE_FILENAME'] : config('CACHE_FILENAME');
            $this->mc_handle = cls_filecache::factory($cache_file_name);
        }
        else if( self::$cache_type == 'memcached' )
        {
            $cache_host = isset($config['CACHE_HOST']) ? $config['CACHE_HOST'] : config('CACHE_HOST');
            $this->mc_handle = new Memcache();
            $servers = array();
            foreach($cache_host as $k => $mcs) 
            {
                $mc_hosts = parse_url ( $mcs );
                $this->mc_handle->addServer( $mc_hosts['host'], $mc_hosts['port'] );
            }
        }
        else if (self::$cache_type == 'memcache')
        {            
            $host = isset($config['CACHE_HOST']) ? $config['CACHE_HOST'] : config('CACHE_HOST');
            $this->mc_handle = new Memcache();
            $mc_hosts = parse_url ( $host[0] );
            $re = $this->mc_handle->connect( $mc_hosts['host'], $mc_hosts['port'], config('CACHE_TIME_OUT') );
            if (!$re) $this->mc_handle = null;
        }
        else 
        {
            return;
        }
    }
    
   /**
    * 为自己创建实例，以方便对主要方法进行静态调用
    */
    protected static function _check_instance($config = array())
    {
        if( !config('CACHE_ENABLE') ) 
        {
            return false;
        }

        if( self::$instance == null ) 
        {
            self::$instance = new cache($config);
        }

        return self::$instance;
    }
   
   /**
    * 获取key
    */
    protected static function _get_key($prefix, $key)
    {
        $key = base64_encode(cache::$df_prefix.'_'.$prefix.'_'.$key);
        if( strlen($key) > 32 ) $key = md5( $key );
        return $key;
    }
   
    private static function _get_config_md5($config)
    {
        return md5(json_encode($config));
    }
    
    
   /**
    * 增加/修改一个缓存
    * @param $prefix     前缀
    * @parem $key        键(key=base64($prefix.'_'.$key))
    * @param $value      值
    * @parem $cachetime  有效时间(0不限, -1使用系统默认)
    * @return void
    */               
    public static function set($prefix, $key, $value, $cachetime = -1)
    {
        if( self::_check_instance() === false )
        {
            return false;
        }
        if (self::$instance->mc_handle == null)
        {
            return false;
        }


        if($cachetime == -1) 
        {
            $cachetime = self::$cache_time;
        }

        $key = self::_get_key($prefix, $key);
       
        if( self::$need_mem ) 
        {
            self::$instance->mc_handle->caches[ $key ] = $value;
        }

        $value = json_encode($value);
        return self::$instance->mc_handle->set($key, $value, 0, $cachetime);
    }
    
   /**
    * 删除缓存
    * @param $prefix     前缀
    * @parem $key        键
    * @return void
    */               
    public static function del($prefix, $key)
    {
        if( self::_check_instance()===false )
        {
            return false;
        }
        if (self::$instance->mc_handle == null)
        {
            return false;
        }
        $key = self::_get_key($prefix, $key);

        if( isset(self::$instance->mc_handle->caches[ $key ]) ) 
        {
            self::$instance->mc_handle->caches[ $key ] = false;
            unset(self::$instance->mc_handle->caches[ $key ]);
        }

        return self::$instance->mc_handle->delete( $key );
    }
    
   /**
    * 读取缓存, 如果没有当前缓存返回false
    * @param $prefix     前缀
    * @parem $key        键
    * @return void
    */               
    public static function get($prefix, $key)
    {
        if( self::_check_instance()===false ) {
            return false;
        }
        if (self::$instance->mc_handle == null)
        {
            return false;
        }

        $key = self::_get_key($prefix, $key);

        if( isset(self::$instance->mc_handle->caches[ $key ]) ) 
        {
            return self::$instance->mc_handle->caches[ $key ];
        }

        $value = self::$instance->mc_handle->get( $key );
        $re = json_decode($value, true);
        return $re;
    }
    
   /**
    * 清除保存在缓存类的缓存
    * @return void
    */               
    public static function free_mem()
    {
        if( isset(self::$instance->mc_handle->caches) ) 
        {
            self::$instance->mc_handle->caches = array();
        }
    }
    
   /**
    * 关闭链接
    * @return void
    */               
    public static function free()
    {
        if( self::_check_instance()===false )
        {
            return false;
        }
        if (self::$instance->mc_handle == null)
        {
            return false;
        }

        self::$instance->mc_handle->close();
    }

    /**
     * 清除所有的缓存数据, 没有释放资源，它仅仅将所有的缓存标记为过期
     */
    public static function flush()
    {
        if( self::_check_instance()===false ) 
        {
            return false;
        }
        if (self::$instance->mc_handle == null)
        {
            return false;
        }

        if (self::$cache_type == 'file') 
        {
            return self::$instance->mc_handle->clear();
        }
        else 
        {
            return self::$instance->mc_handle->flush();
        }
    }

    
   /**
    * 重设cache参数(使用其它缓存文件)
    * @return void
    */               
    public static function reconfig( $config )
    {
        if (empty($config)) 
        {
            return false;
        }
        
        if( self::$instance != null )
        {
            //和上次配置一样就保持原来的
            if (self::$cache_config_md5 == self::_get_config_md5($config))
            {
                return self::$instance;
            }
            
            self::flush();
            self::free();
            self::$instance = null;
        }

        /* cache重新配置 */
/*         config('CACHE_ENABLE'   ,$config['CACHE_ENABLE']);
        config('CACHE_TYPE'     ,$config['CACHE_TYPE']);
        config('CACHE_TIME'     ,$config['CACHE_TIME']);
        config('CACHE_FILENAME' ,$config['CACHE_FILENAME']);
        config('CACHE_PREFIX'   ,$config['CACHE_PREFIX']);
        config('CACHE_TIME_OUT' ,$config['CACHE_TIME_OUT']);
        config('CACHE_HOST'     ,$config['CACACHE_HOSTCHE_ENABLE']); */

        return self::_check_instance($config);
    }


    /**
     * 使用默认cache参数
     * @return void
     */
    public static function defconfig()
    {
        if( self::$instance != null )
        {
            //和上次配置一样就保持原来的
            if (self::$cache_config_md5 == self::_get_config_md5(array()))
            {
                return self::$instance;
            }
            
            self::flush();
            self::free();
            self::$instance = null;
        }
        
        return self::_check_instance();
    }
}


